import random
import tkinter as tk
from tkinter import scrolledtext, messagebox
from sympy import isprime, mod_inverse

#生成指定位数的奇数作为素数候选
def create_prime_candidate(bits):
    candidate = random.getrandbits(bits)
    candidate |= (1 << bits - 1) | 1
    return candidate

#生成指定位数的大素数
def generate_big_prime(bits):
    candidate = 4
    while not isprime(candidate):
        candidate = create_prime_candidate(bits)
    return candidate

#RSA密钥生成
def create_rsa_keys(key_strength):
    p = generate_big_prime(key_strength)
    q = generate_big_prime(key_strength)
    n = p * q
    phi = (p - 1) * (q - 1)
    e = 65537
    d = mod_inverse(e, phi)
    return ((e, n), (d, n))

#RSA加密解密
def rsa_encrypt(public_key, plain_data):
    e, n = public_key
    return pow(plain_data, e, n)

def rsa_decrypt(private_key, cipher_data):
    d, n = private_key
    return pow(cipher_data, d, n)

#RSA同态乘法
def rsa_homomorphic_multiply(cipher1, cipher2, public_key):
    _, n = public_key
    return (cipher1 * cipher2) % n

#生成Paillier密钥对
def generate_paillier_keys(key_length):
    p = generate_big_prime(key_length // 2)
    q = generate_big_prime(key_length // 2)
    n = p * q
    lambda_val = (p - 1) * (q - 1)
    g = n + 1  # 标准g值
    mu = mod_inverse(lambda_val, n)
    return (n, g), (lambda_val, mu, n)

#Paillier加密
def paillier_encrypt(pk, plain_data):
    n, g = pk
    r = random.randint(1, n - 1)
    return (pow(g, plain_data, n ** 2) * pow(r, n, n ** 2)) % n ** 2

#Paillier解密
def paillier_decrypt(sk, cipher_data):
    lambda_val, mu, n = sk
    x = pow(cipher_data, lambda_val, n ** 2)
    L = (x - 1) // n
    return (L * mu) % n

#Paillier同态加法
def paillier_homomorphic_add(cipher1, cipher2, pk):
    n, _ = pk
    return (cipher1 * cipher2) % n ** 2

#混合密钥管理系统
#生成RSA和Paillier组合密钥
def generate_combined_keys(key_strength):
    rsa_public, rsa_private = create_rsa_keys(key_strength)
    paillier_public, paillier_private = generate_paillier_keys(key_strength)
    return {
        'rsa': {
            'public': rsa_public,
            'private': rsa_private
        },
        'paillier': {
            'public': paillier_public,
            'private': paillier_private
        }
    }

# 全局密钥存储
combined_keys = None

#用户界面实现
#创建子窗口
def create_child_window(parent, title, size=None):
    window = tk.Toplevel(parent)
    window.title(title)
    if size:
        window.geometry(size)
    return window

# 密钥生成界面
def show_key_generation():
    def generate_and_display():
        strength = int(key_strength.get())
        global combined_keys
        combined_keys = generate_combined_keys(strength)
        key_display.delete(1.0, tk.END)
        key_display.insert(tk.END, "=== RSA 密钥 ===\n")
        key_display.insert(tk.END, f"公钥(e,n): {combined_keys['rsa']['public']}\n")
        key_display.insert(tk.END, f"私钥(d,n): {combined_keys['rsa']['private']}\n\n")
        key_display.insert(tk.END, "=== Paillier 密钥 ===\n")
        key_display.insert(tk.END, f"公钥(n,g): {combined_keys['paillier']['public']}\n")
        key_display.insert(tk.END,
                           f"私钥(λ,μ): ({combined_keys['paillier']['private'][0]}, {combined_keys['paillier']['private'][1]})")
    key_window = create_child_window(root, "密钥生成器", "500x400")
    # 密钥强度选择
    tk.Label(key_window, text="选择密钥强度:").pack(pady=5)
    key_strength = tk.StringVar(value="16")
    strength_menu = tk.OptionMenu(key_window, key_strength, "16", "32", "64", "128")
    strength_menu.pack(pady=5)
    # 生成按钮
    generate_btn = tk.Button(key_window, text="生成密钥对", command=generate_and_display,
                             bg="#4CAF50", fg="white")
    generate_btn.pack(pady=10)
    # 密钥显示区域
    key_display = scrolledtext.ScrolledText(key_window, width=60, height=15)
    key_display.pack(pady=10)


# 加密功能界面
def show_encryption_interface():
    def perform_encryption():
        try:
            plain_data = int(data_entry.get("1.0", tk.END).strip())
            if not combined_keys:
                messagebox.showerror("错误", "请先生成密钥对！")
                return
            if enc_type.get() == "RSA":
                cipher = rsa_encrypt(combined_keys['rsa']['public'], plain_data)
                result_var.set(f"RSA加密结果: {cipher}")
            else:  # Paillier
                cipher = paillier_encrypt(combined_keys['paillier']['public'], plain_data)
                result_var.set(f"Paillier加密结果: {cipher}")
        except ValueError:
            messagebox.showerror("输入错误", "请输入有效的整数参数！")
    enc_window = create_child_window(root, "数据加密", "450x350")
    # 加密类型选择
    tk.Label(enc_window, text="选择加密类型:").pack(pady=5)
    enc_type = tk.StringVar(value="RSA")
    tk.Radiobutton(enc_window, text="RSA加密", variable=enc_type, value="RSA").pack()
    tk.Radiobutton(enc_window, text="Paillier加密", variable=enc_type, value="Paillier").pack()
    # 明文输入
    tk.Label(enc_window, text="明文数据:").pack(pady=5)
    data_entry = tk.Text(enc_window, height=2)
    data_entry.pack(pady=5)
    # 加密按钮
    encrypt_btn = tk.Button(enc_window, text="加密", command=perform_encryption,
                            bg="#2196F3", fg="white")
    encrypt_btn.pack(pady=10)
    # 结果显示
    result_var = tk.StringVar()
    tk.Label(enc_window, textvariable=result_var, font=('Arial', 10)).pack(pady=10)

# 同态操作界面
def show_homomorphic_operation():
    def perform_operation():
        try:
            cipher1 = int(entry1.get("1.0", tk.END).strip())
            cipher2 = int(entry2.get("1.0", tk.END).strip())

            if op_type.get() == "乘法":
                result = rsa_homomorphic_multiply(cipher1, cipher2, combined_keys['rsa']['public'])
                result_var.set(f"同态乘法结果: {result}")
            else:  # 加法
                result = paillier_homomorphic_add(cipher1, cipher2, combined_keys['paillier']['public'])
                result_var.set(f"同态加法结果: {result}")
        except ValueError:
            messagebox.showerror("输入错误", "请输入有效的密文！")
    op_window = create_child_window(root, "同态运算", "450x350")
    # 操作类型选择
    tk.Label(op_window, text="选择同态运算类型:").pack(pady=5)
    op_type = tk.StringVar(value="乘法")
    tk.Radiobutton(op_window, text="乘法同态(RSA)", variable=op_type, value="乘法").pack()
    tk.Radiobutton(op_window, text="加法同态(Paillier)", variable=op_type, value="加法").pack()
    # 密文输入
    tk.Label(op_window, text="密文1:").pack(pady=5)
    entry1 = tk.Text(op_window, height=2)
    entry1.pack(pady=5)
    tk.Label(op_window, text="密文2:").pack(pady=5)
    entry2 = tk.Text(op_window, height=2)
    entry2.pack(pady=5)
    # 计算按钮
    calc_btn = tk.Button(op_window, text="计算", command=perform_operation,
                         bg="#9C27B0", fg="white")
    calc_btn.pack(pady=10)
    # 结果显示
    result_var = tk.StringVar()
    tk.Label(op_window, textvariable=result_var, font=('Arial', 10)).pack(pady=10)

# 安全投票系统（使用两种同态）
def launch_voting_system():
    if not combined_keys:
        messagebox.showerror("错误", "请先生成密钥对！")
        return
    vote_window = create_child_window(root, "安全投票系统", "700x600")
    candidates = ["候选人A", "候选人B", "候选人C"]
    encrypted_ballots = []
    # 投票面板
    voting_panel = tk.LabelFrame(vote_window, text="投票面板", padx=15, pady=15)
    voting_panel.pack(pady=15, fill="both", expand=True, padx=15)
    tk.Label(voting_panel, text="请选择您的投票选项:", font=('Arial', 10, 'bold')).pack(anchor="w", pady=5)
    selected_option = tk.StringVar(value=candidates[0])
    for candidate in candidates:
        tk.Radiobutton(voting_panel, text=candidate, variable=selected_option, value=candidate).pack(anchor="w", pady=2)

    def submit_vote():
        choice = candidates.index(selected_option.get()) + 1  # 编码为1,2,3
        # 使用RSA加密投票选项（用于乘法同态统计）
        rsa_encrypted = rsa_encrypt(combined_keys['rsa']['public'], choice)
        # 使用Paillier加密1（用于加法同态计数）
        paillier_encrypted = paillier_encrypt(combined_keys['paillier']['public'], 1)
        encrypted_ballots.append((rsa_encrypted, paillier_encrypted))
        messagebox.showinfo("成功", "投票已提交！")
    tk.Button(voting_panel, text="提交投票", command=submit_vote, bg="#FF9800", fg="white").pack(pady=15)
    # 计票面板
    tally_panel = tk.LabelFrame(vote_window, text="计票面板", padx=15, pady=15)
    tally_panel.pack(pady=15, fill="both", expand=True, padx=15)

    def calculate_results():
        if not encrypted_ballots:
            messagebox.showwarning("提示", "暂无投票数据！")
            return
        # 使用RSA乘法同态统计乘积（候选人分布）
        rsa_product = 1
        # 使用Paillier加法同态统计总数（总票数）
        paillier_sum = 1  # Paillier加密的初始值
        for rsa_c, paillier_c in encrypted_ballots:
            rsa_product = rsa_homomorphic_multiply(rsa_product, rsa_c, combined_keys['rsa']['public'])
            paillier_sum = paillier_homomorphic_add(paillier_sum, paillier_c, combined_keys['paillier']['public'])
        # 解密结果
        decrypted_product = rsa_decrypt(combined_keys['rsa']['private'], rsa_product)
        total_votes = paillier_decrypt(combined_keys['paillier']['private'], paillier_sum)
        # 分析投票结果
        results = {candidate: 0 for candidate in candidates}
        temp = decrypted_product
        while temp > 0:
            digit = temp % 10
            if 1 <= digit <= len(candidates):
                results[candidates[digit - 1]] += 1
            temp = temp // 10
        # 显示结果
        result_text = scrolledtext.ScrolledText(tally_panel, width=70, height=15)
        result_text.pack()
        result_text.insert(tk.END, "=== 投票统计结果 ===\n\n")
        result_text.insert(tk.END, f"总投票数(Paillier统计): {total_votes}\n\n")
        result_text.insert(tk.END, "候选人得票分布(RSA统计):\n")
        for candidate, votes in results.items():
            result_text.insert(tk.END, f"{candidate}: {votes}票\n")
        result_text.config(state="disabled")
    tk.Button(tally_panel, text="统计结果", command=calculate_results, bg="#9C27B0", fg="white").pack(pady=10)


#主程序界面
def setup_main_interface():
    root.title("混合同态加密系统")
    root.geometry("600x500")
    root.configure(bg="#f5f5f5")
    # 标题
    header = tk.Frame(root, bg="#3F51B5")
    header.pack(fill="x", pady=(0, 20))
    tk.Label(header, text="混合同态加密系统", font=('Arial', 16, 'bold'),
             bg="#3F51B5", fg="white", padx=20, pady=15).pack()
    # 主功能按钮
    button_frame = tk.Frame(root, bg="#f5f5f5")
    button_frame.pack(pady=10)
    btn_style = {'width': 20, 'height': 2, 'font': ('Arial', 10)}
    tk.Button(button_frame, text="密钥管理", command=show_key_generation,
              bg="#607D8B", fg="white", **btn_style).grid(row=0, column=0, pady=10, padx=10)
    tk.Button(button_frame, text="数据加密", command=show_encryption_interface,
              bg="#009688", fg="white", **btn_style).grid(row=0, column=1, pady=10, padx=10)
    tk.Button(button_frame, text="同态运算", command=show_homomorphic_operation,
              bg="#673AB7", fg="white", **btn_style).grid(row=1, column=0, pady=10, padx=10)
    tk.Button(button_frame, text="安全投票", command=launch_voting_system,
              bg="#FF5722", fg="white", **btn_style).grid(row=1, column=1, pady=10, padx=10)
    # 状态栏
    status_bar = tk.Frame(root, bg="#3F51B5", height=30)
    status_bar.pack(fill="x", side=tk.BOTTOM)
    tk.Label(status_bar, text="混合同态加密系统 | RSA(乘法) + Paillier(加法)",
             bg="#3F51B5", fg="white").pack(side=tk.RIGHT, padx=10)

#主程序入口
if __name__ == "__main__":
    root = tk.Tk()
    setup_main_interface()
    root.mainloop()